home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #1 / Ham Radio 2000.iso / ham2000 / tcp_ip / wnos / wn941101 / ip.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-10  |  12.8 KB  |  503 lines

  1. /* Upper half of IP, consisting of send/receive primitives, including
  2.  * fragment reassembly, for higher level protocols.
  3.  * Not needed when running as a standalone gateway.
  4.  */
  5. #include "global.h"
  6. #include "mbuf.h"
  7. #include "timer.h"
  8. #include "internet.h"
  9. #include "netuser.h"
  10. #include "iface.h"
  11. #include "pktdrvr.h"
  12. #include "ip.h"
  13. #include "icmp.h"
  14.  
  15. static struct mbuf * near fraghandle __ARGS((struct ip *ip,struct mbuf *bp));
  16. static void ip_timeout __ARGS((void *arg));
  17. static void near free_reasm __ARGS((struct reasm *rp));
  18. static void near freefrag __ARGS((struct frag *fp));
  19. static struct reasm * near lookup_reasm __ARGS((struct ip *ip));
  20. static struct reasm * near creat_reasm __ARGS((struct ip *ip));
  21. static struct frag * near newfrag __ARGS((int16 offset,int16 last,struct mbuf *bp));
  22.  
  23. struct mib_entry Ip_mib[20] = {
  24.     "",                    0,
  25.     "Forwarding",        1,
  26.     "DefaultTTL",        MAXTTL,
  27.     "InReceives",        0,
  28.     "InHdrErrors",        0,
  29.     "InAddrErrors",        0,
  30.     "ForwDatagrams",    0,
  31.     "InUnknownProtos",    0,
  32.     "InDiscards",        0,
  33.     "InDelivers",        0,
  34.     "OutRequests",        0,
  35.     "OutDiscards",        0,
  36.     "OutNoRoutes",        0,
  37.     "ReasmTimeout",        TLB,
  38.     "ReasmReqds",        0,
  39.     "ReasmOKs",            0,
  40.     "ReasmFails",        0,
  41.     "FragOKs",            0,
  42.     "FragFails",        0,
  43.     "FragCreates",        0,
  44. };
  45.  
  46. struct reasm *Reasmq;
  47. static struct raw_ip *Raw_ip;
  48.  
  49. #define    INSERT    0
  50. #define    APPEND    1
  51. #define    PREPEND    2
  52.  
  53. /* Send an IP datagram. Modeled after the example interface on p 32 of
  54.  * RFC 791
  55.  */
  56. int
  57. ip_send(source,dest,protocol,tos,ttl,bp,length,id,df)
  58. int32 source;            /* source address */
  59. int32 dest;                /* Destination address */
  60. char protocol;            /* Protocol */
  61. char tos;                /* Type of service */
  62. char ttl;                /* Time-to-live */
  63. struct mbuf *bp;        /* Data portion of datagram */
  64. int16 length;            /* Optional length of data portion */
  65. int16 id;                /* Optional identification */
  66. char df;                /* Don't-fragment flag */
  67. {
  68.     struct mbuf *tbp;
  69.     struct ip ip;            /* Pointer to IP header */
  70.     static int16 id_cntr;    /* Datagram serial number */
  71.     struct phdr phdr;
  72.  
  73.     ipOutRequests++;
  74.  
  75.     if(source == INADDR_ANY)
  76.         source = locaddr(dest);
  77.     if(length == 0 && bp != NULLBUF)
  78.         length = len_p(bp);
  79.     if(id == 0)
  80.         id = id_cntr++;
  81.     if(ttl == 0)
  82.         ttl = ipDefaultTTL;
  83.  
  84.     /* Fill in IP header */
  85.     ip.version = IPVERSION;
  86.     ip.tos = tos;
  87.     ip.length = IPLEN + length;
  88.     ip.id = id;
  89.     ip.flags.mf = ip.flags.congest = ip.optlen = ip.offset = 0;
  90.     ip.flags.df = df;
  91.     ip.ttl = ttl;
  92.     ip.protocol = protocol;
  93.     ip.source = source;
  94.     ip.dest = dest;
  95.     if((tbp = htonip(&ip,bp,0)) == NULLBUF){
  96.         free_p(bp);
  97.         return -1;
  98.     }
  99.     if((bp = pushdown(tbp,sizeof(phdr))) == NULLBUF){
  100.         free_p(tbp);
  101.         return -1;
  102.     }
  103.     if(ismyaddr(ip.dest)){
  104.         /* Pretend it has been sent by the loopback interface before
  105.          * it appears in the receive queue
  106.          */
  107.         phdr.iface = &Loopback;
  108.         Loopback.ipsndcnt++;
  109.         Loopback.rawsndcnt++;
  110.         Loopback.lastsent = secclock();
  111.     } else
  112.         phdr.iface = NULLIF;
  113.     phdr.type = CL_NONE;
  114.     memcpy(&bp->data[0],(char *)&phdr,sizeof(phdr));
  115.     enqueue(&Hopper,bp);
  116.     return 0;
  117. }
  118.  
  119. /* Reassemble incoming IP fragments and dispatch completed datagrams
  120.  * to the proper transport module
  121.  */
  122. void
  123. ip_recv(iface,ip,bp,rxbroadcast)
  124. struct iface *iface;    /* Incoming interface */
  125. struct ip *ip;            /* Extracted IP header */
  126. struct mbuf *bp;        /* Data portion */
  127. int rxbroadcast;        /* True if received on subnet broadcast address */
  128. {
  129.     /* Function to call with completed datagram */
  130.     struct raw_ip *rp;
  131.     struct mbuf *bp1,*tbp;
  132.     int rxcnt = 0;
  133.     register struct iplink *ipp;
  134.  
  135.     /* If we have a complete packet, call the next layer
  136.      * to handle the result. Note that fraghandle passes back
  137.      * a length field that does NOT include the IP header
  138.      */
  139.     if((bp = fraghandle(ip,bp)) == NULLBUF)
  140.         return;        /* Not done yet */
  141.  
  142.     ipInDelivers++;
  143.  
  144.     for(rp = Raw_ip;rp != NULLRIP;rp = rp->next){
  145.         if(rp->protocol != ip->protocol)
  146.             continue;
  147.         rxcnt++;
  148.         /* Duplicate the data portion, and put the header back on */
  149.         dup_p(&bp1,bp,0,len_p(bp));
  150.         if(bp1 != NULLBUF && (tbp = htonip(ip,bp1,1)) != NULLBUF){
  151.             enqueue(&rp->rcvq,tbp);
  152.             if(rp->r_upcall != NULLVFP)
  153.                 (*rp->r_upcall)(rp);
  154.         } else {
  155.             free_p(bp1);
  156.         }
  157.     }
  158.     /* Look it up in the transport protocol table */
  159.     for(ipp = Iplink;ipp->funct != NULL;ipp++){
  160.         if(ipp->proto == ip->protocol)
  161.             break;
  162.     }
  163.     if(ipp->funct != NULL){
  164.         /* Found, call transport protocol */
  165.         (*ipp->funct)(iface,ip,bp,rxbroadcast);
  166.     } else {
  167.         /* Not found */
  168.         if(rxcnt == 0) {
  169.             /* Send an ICMP Protocol Unknown response... */
  170.             ipInUnknownProtos++;
  171.             /* ...unless it's a broadcast */
  172.             if(!rxbroadcast){
  173.                 icmp_output(ip,bp,ICMP_DEST_UNREACH,
  174.                     ICMP_PROT_UNREACH,NULLICMP);
  175.             }
  176.         }
  177.         free_p(bp);
  178.     }
  179. }
  180. /* Handle IP packets encapsulated inside IP */
  181. void
  182. ipip_recv(iface,ip,bp,rxbroadcast)
  183. struct iface *iface;    /* Incoming interface */
  184. struct ip *ip;            /* Extracted IP header */
  185. struct mbuf *bp;        /* Data portion */
  186. int rxbroadcast;        /* True if received on subnet broadcast address */
  187. {
  188.     struct phdr phdr;
  189.     struct mbuf *tbp;
  190.  
  191.     if((tbp = pushdown(bp,sizeof(phdr))) == NULLBUF){
  192.         free_p(bp);
  193.         return;
  194.     }
  195.     bp = tbp;
  196.     phdr.iface = &Encap;
  197.     phdr.type = CL_NONE;
  198.     memcpy(&bp->data[0],(char *)&phdr,sizeof(phdr));
  199.     enqueue(&Hopper,bp);
  200. }
  201.  
  202. /* Process IP datagram fragments
  203.  * If datagram is complete, return it with ip->length containing the data
  204.  * length (MINUS header); otherwise return NULLBUF
  205.  */
  206. static struct mbuf * near
  207. fraghandle(ip,bp)
  208. struct ip *ip;            /* IP header, host byte order */
  209. struct mbuf *bp;        /* The fragment itself */
  210. {
  211.     struct reasm *rp;     /* Pointer to reassembly descriptor */
  212.     struct frag *lastfrag,*nextfrag,*tfp;
  213.     struct mbuf *tbp;
  214.     int16 i;
  215.     int16 last;        /* Index of first byte beyond fragment */
  216.  
  217.     last = ip->offset + ip->length - (IPLEN + ip->optlen);
  218.  
  219.     rp = lookup_reasm(ip);
  220.     if(ip->offset == 0 && !ip->flags.mf){
  221.         /* Complete datagram received. Discard any earlier fragments */
  222.         if(rp != NULLREASM){
  223.             free_reasm(rp);
  224.             ipReasmOKs++;
  225.         }
  226.         return bp;
  227.     }
  228.     ipReasmReqds++;
  229.     if(rp == NULLREASM){
  230.         /* First fragment; create new reassembly descriptor */
  231.         if((rp = creat_reasm(ip)) == NULLREASM){
  232.             /* No space for descriptor, drop fragment */
  233.             ipReasmFails++;
  234.             free_p(bp);
  235.             return NULLBUF;
  236.         }
  237.     }
  238.     /* Keep restarting timer as long as we keep getting fragments */
  239.     stop_timer(&rp->timer);
  240.     start_timer(&rp->timer);
  241.  
  242.     /* If this is the last fragment, we now know how long the
  243.      * entire datagram is; record it
  244.      */
  245.     if(!ip->flags.mf)
  246.         rp->length = last;
  247.  
  248.     /* Set nextfrag to the first fragment which begins after us,
  249.      * and lastfrag to the last fragment which begins before us
  250.      */
  251.     lastfrag = NULLFRAG;
  252.     for(nextfrag = rp->fraglist;nextfrag != NULLFRAG;nextfrag = nextfrag->next){
  253.         if(nextfrag->offset > ip->offset)
  254.             break;
  255.         lastfrag = nextfrag;
  256.     }
  257.     /* Check for overlap with preceeding fragment */
  258.     if(lastfrag != NULLFRAG  && ip->offset < lastfrag->last){
  259.         /* Strip overlap from new fragment */
  260.         i = lastfrag->last - ip->offset;
  261.         pullup(&bp,NULLCHAR,i);
  262.         if(bp == NULLBUF)
  263.             return NULLBUF;    /* Nothing left */
  264.         ip->offset += i;
  265.     }
  266.     /* Look for overlap with succeeding segments */
  267.     for(; nextfrag != NULLFRAG; nextfrag = tfp){
  268.         tfp = nextfrag->next;    /* save in case we delete fp */
  269.  
  270.         if(nextfrag->offset >= last)
  271.             break;    /* Past our end */
  272.         /* Trim the front of this entry; if nothing is
  273.          * left, remove it.
  274.          */
  275.         i = last - nextfrag->offset;
  276.         pullup(&nextfrag->buf,NULLCHAR,i);
  277.         if(nextfrag->buf == NULLBUF){
  278.             /* superseded; delete from list */
  279.             if(nextfrag->prev != NULLFRAG)
  280.                 nextfrag->prev->next = nextfrag->next;
  281.             else
  282.                 rp->fraglist = nextfrag->next;
  283.             if(tfp->next != NULLFRAG)
  284.                 nextfrag->next->prev = nextfrag->prev;
  285.             freefrag(nextfrag);
  286.         } else
  287.             nextfrag->offset = last;
  288.     }
  289.     /* Lastfrag now points, as before, to the fragment before us;
  290.      * nextfrag points at the next fragment. Check to see if we can
  291.      * join to either or both fragments.
  292.      */
  293.     i = INSERT;
  294.     if(lastfrag != NULLFRAG && lastfrag->last == ip->offset)
  295.         i |= APPEND;
  296.     if(nextfrag != NULLFRAG && nextfrag->offset == last)
  297.         i |= PREPEND;
  298.     switch(i){
  299.     case INSERT:    /* Insert new desc between lastfrag and nextfrag */
  300.         tfp = newfrag(ip->offset,last,bp);
  301.         tfp->prev = lastfrag;
  302.         tfp->next = nextfrag;
  303.         if(lastfrag != NULLFRAG)
  304.             lastfrag->next = tfp;    /* Middle of list */
  305.         else
  306.             rp->fraglist = tfp;    /* First on list */
  307.         if(nextfrag != NULLFRAG)
  308.             nextfrag->prev = tfp;
  309.         break;
  310.     case APPEND:    /* Append to lastfrag */
  311.         append(&lastfrag->buf,bp);
  312.         lastfrag->last = last;    /* Extend forward */
  313.         break;
  314.     case PREPEND:    /* Prepend to nextfrag */
  315.         tbp = nextfrag->buf;
  316.         nextfrag->buf = bp;
  317.         append(&nextfrag->buf,tbp);
  318.         nextfrag->offset = ip->offset;    /* Extend backward */
  319.         break;
  320.     case (APPEND|PREPEND):
  321.         /* Consolidate by appending this fragment and nextfrag
  322.          * to lastfrag and removing the nextfrag descriptor
  323.          */
  324.         append(&lastfrag->buf,bp);
  325.         append(&lastfrag->buf,nextfrag->buf);
  326.         nextfrag->buf = NULLBUF;
  327.         lastfrag->last = nextfrag->last;
  328.  
  329.         /* Finally unlink and delete the now unneeded nextfrag */
  330.         lastfrag->next = nextfrag->next;
  331.         if(nextfrag->next != NULLFRAG)
  332.             nextfrag->next->prev = lastfrag;
  333.         freefrag(nextfrag);
  334.         break;
  335.     }
  336.     if(rp->fraglist->offset == 0 && rp->fraglist->next == NULLFRAG
  337.       && rp->length != 0){
  338.         /* We've gotten a complete datagram, so extract it from the
  339.          * reassembly buffer and pass it on.
  340.          */
  341.         bp = rp->fraglist->buf;
  342.         rp->fraglist->buf = NULLBUF;
  343.         /* Tell IP the entire length */
  344.         ip->length = rp->length + (IPLEN + ip->optlen);
  345.         free_reasm(rp);
  346.         ipReasmOKs++;
  347.         return bp;
  348.     } else
  349.         return NULLBUF;
  350. }
  351.  
  352. /* Arrange for receipt of raw IP datagrams */
  353. struct raw_ip *
  354. raw_ip(protocol,r_upcall)
  355. int protocol;
  356. void (*r_upcall)();
  357. {
  358.     struct raw_ip *rp = (struct raw_ip *)mxallocw(sizeof(struct raw_ip));
  359.     rp->protocol = protocol;
  360.     rp->r_upcall = r_upcall;
  361.     rp->next = Raw_ip;
  362.     Raw_ip = rp;
  363.     return rp;
  364. }
  365.  
  366. /* Free a raw IP descriptor */
  367. void
  368. del_ip(rpp)
  369. struct raw_ip *rpp;
  370. {
  371.     struct raw_ip *rplast = NULLRIP;
  372.     struct raw_ip *rp;
  373.  
  374.     /* Do sanity check on arg */
  375.     for(rp = Raw_ip; rp != NULLRIP; rplast = rp, rp = rp->next)
  376.         if(rp == rpp)
  377.             break;
  378.     if(rp == NULLRIP)
  379.         return;    /* Doesn't exist */
  380.  
  381.     /* Unlink */
  382.     if(rplast != NULLRIP)
  383.         rplast->next = rp->next;
  384.     else
  385.         Raw_ip = rp->next;
  386.     /* Free resources */
  387.     free_q(&rp->rcvq);
  388.     xfree((char *)rp);
  389. }
  390.  
  391. static struct reasm * near
  392. lookup_reasm(ip)
  393. struct ip *ip;
  394. {
  395.     register struct reasm *rp;
  396.     struct reasm *rplast = NULLREASM;
  397.  
  398.     for(rp = Reasmq;rp != NULLREASM;rplast=rp,rp = rp->next){
  399.         if(ip->id == rp->id && ip->source == rp->source
  400.          && ip->dest == rp->dest && ip->protocol == rp->protocol){
  401.             if(rplast != NULLREASM){
  402.                 /* Move to top of list for speed */
  403.                 rplast->next = rp->next;
  404.                 rp->next = Reasmq;
  405.                 Reasmq = rp;
  406.             }
  407.             return rp;
  408.         }
  409.     }
  410.     return NULLREASM;
  411. }
  412. /* Create a reassembly descriptor,
  413.  * put at head of reassembly list
  414.  */
  415. static struct reasm * near
  416. creat_reasm(ip)
  417. register struct ip *ip;
  418. {
  419.     register struct reasm *rp;
  420.  
  421.     if((rp = (struct reasm *)mxallocw(sizeof(struct reasm))) == NULLREASM)
  422.         return rp;    /* No space for descriptor */
  423.     rp->source = ip->source;
  424.     rp->dest = ip->dest;
  425.     rp->id = ip->id;
  426.     rp->protocol = ip->protocol;
  427.     set_timer(&rp->timer,ipReasmTimeout * 1000L);
  428.     rp->timer.func = (void (*) __ARGS((void *))) ip_timeout;
  429.     rp->timer.arg = rp;
  430.  
  431.     rp->next = Reasmq;
  432.     Reasmq = rp;
  433.     return rp;
  434. }
  435.  
  436. /* Free all resources associated with a reassembly descriptor */
  437. static void near
  438. free_reasm(r)
  439. struct reasm *r;
  440. {
  441.     register struct reasm *rp;
  442.     struct reasm *rplast = NULLREASM;
  443.     register struct frag *fp;
  444.  
  445.     for(rp = Reasmq;rp != NULLREASM;rplast = rp,rp=rp->next)
  446.         if(r == rp)
  447.             break;
  448.     if(rp == NULLREASM)
  449.         return;    /* Not on list */
  450.  
  451.     stop_timer(&rp->timer);
  452.     /* Remove from list of reassembly descriptors */
  453.     if(rplast != NULLREASM)
  454.         rplast->next = rp->next;
  455.     else
  456.         Reasmq = rp->next;
  457.  
  458.     /* Free any fragments on list, starting at beginning */
  459.     while((fp = rp->fraglist) != NULLFRAG){
  460.         rp->fraglist = fp->next;
  461.         free_p(fp->buf);
  462.         xfree((char *)fp);
  463.     }
  464.     xfree((char *)rp);
  465. }
  466.  
  467. /* Handle reassembly timeouts by deleting all reassembly resources */
  468. static void
  469. ip_timeout(arg)
  470. void *arg;
  471. {
  472.     struct reasm *rp = (struct reasm *)arg;
  473.     free_reasm(rp);
  474.     ipReasmFails++;
  475. }
  476. /* Create a fragment */
  477. static struct frag * near
  478. newfrag(offset,last,bp)
  479. int16 offset,last;
  480. struct mbuf *bp;
  481. {
  482.     struct frag *fp;
  483.  
  484.     if((fp = (struct frag *)mxallocw(sizeof(struct frag))) == NULLFRAG){
  485.         /* Drop fragment */
  486.         free_p(bp);
  487.         return NULLFRAG;
  488.     }
  489.     fp->buf = bp;
  490.     fp->offset = offset;
  491.     fp->last = last;
  492.     return fp;
  493. }
  494. /* Delete a fragment, return next one on queue */
  495. static void near
  496. freefrag(fp)
  497. struct frag *fp;
  498. {
  499.     free_p(fp->buf);
  500.     xfree((char *)fp);
  501. }
  502.  
  503.